#include <cstdio>
#include <mpi.h>
#include "MPIUtil.h"

MPIUtil::MPIUtil() {
}

MPIUtil::MPIUtil(int& argc, char* argv[]) {
    init(argc, argv);
}

MPIUtil::~MPIUtil() {
}

void MPIUtil::init(int& argc, char* argv[]) {
    MPI_Init(&argc, &argv);
}

void MPIUtil::finalize() {
    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Finalize();
}

void MPIUtil::enviar(int msg, int destino) {
    MPI_Send(&msg, TAMANHO_MENSAGEM, MPI_INT, destino, TAG, MPI_COMM_WORLD);
}

int MPIUtil::receber(int* origem) {
    int dado = -1;
    MPI_Status estado;

    MPI_Recv(&dado, TAMANHO_MENSAGEM, MPI_INT, MPI_ANY_SOURCE, TAG,
            MPI_COMM_WORLD, &estado);
    *origem = estado.MPI_SOURCE;

    return dado;
}

int MPIUtil::receber(int* origem, int timeout) {
    time_t inicio = time(NULL);
    time_t fim = time(NULL);
    bool recebeu = false;
    int dado;

    receberNB(&dado);
    while (!recebeu && (difftime(fim, inicio) < timeout)) {
        recebeu = testaRecerber(origem);
        sleep(1);
        fim = time(NULL);
    }

    return recebeu ? dado : -1;
}

void MPIUtil::receberNB(int* dado) {
    MPI_Irecv(dado, TAMANHO_MENSAGEM, MPI_INT, MPI_ANY_SOURCE, TAG,
            MPI_COMM_WORLD, &requisicao);
}

bool MPIUtil::testaRecerber(int* origem) {
    int retorno;
    MPI_Status estado;

    MPI_Test(&requisicao, &retorno, &estado);

    *origem = estado.MPI_SOURCE;

    return retorno;
}
